﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Xml;
using System.Reflection;
using Coffee.SurveyControls;
using Coffee.SurveyControls.SurveyQuestions;

namespace Coffee
{
    public class SurveyControlFactory
    {
        static Dictionary<string, Type> controltypes;

        public static void RegisterType(Type type)
        {
            if ((typeof(SurveyQuestionRow)).IsAssignableFrom(type))
            {
                if (!ControlTypes.ContainsKey(type.Name))
                    ControlTypes.Add(type.Name, type);
            }
            else
            {
                throw new Exception("Invalid type");
            }
        }

        public static Dictionary<string, Type> ControlTypes
        {
            get
            {
                if (controltypes == null)
                {
                    controltypes = new Dictionary<string, Type>();

                    var types = Assembly
                        .GetExecutingAssembly()
                        .GetTypes()
                        .Where(t => typeof(SurveyControl).IsAssignableFrom(t));

                    foreach (Type type in types)
                    {
                        System.Diagnostics.Debug.WriteLine(type.FullName);
                        controltypes.Add(type.Name, type);
                    }
                }
                return controltypes;
            }
        }

        public static Dictionary<Type, Func<SurveyManager, XmlNode, SurveyControl>> surveyControlProviderDict = new Dictionary<Type, Func<SurveyManager, XmlNode, SurveyControl>>();

        public static SurveyControl Create(SurveyManager parent, XmlNode configuration)
        {
            // Resolve Types...
            string key = configuration.Attributes["type"].Value;

            if (ControlTypes.ContainsKey(key))
            {
                var type = ControlTypes[key];

                Func<SurveyManager, XmlNode, SurveyControl> func = null;

                if (!surveyControlProviderDict.ContainsKey(type))
                {
                    var param1 = Expression.Parameter(typeof(SurveyManager), "parent");
                    var param2 = Expression.Parameter(typeof(XmlNode), "configuration");
                    var ctor = type.GetConstructor(new[] { typeof(SurveyManager), typeof(XmlNode) });
                    var lambda = Expression.Lambda<Func<SurveyManager, XmlNode, SurveyControl>>(
                        Expression.New(ctor, param1, param2), param1, param2);
                    func = lambda.Compile();
                    surveyControlProviderDict.Add(type, func);
                }
                else
                {
                    func = surveyControlProviderDict[type];
                }

                return func(parent, configuration);

            }
            return null;
        }

        public static SurveyControl Create(Type type, SurveyManager parent, XmlNode configuration)
        {
            SurveyControl ctl = (SurveyControl)Reflection.CreateLocalObject(
                    type,
                    new Type[] { typeof(SurveyManager), typeof(XmlNode) },
                    new object[] { parent, configuration }
                );

            return ctl;
        }


    }

}